from datetime import datetime, timedelta
from typing import Optional

from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from jose import JWTError, jwt
from passlib.context import CryptContext
from pydantic import BaseModel
from app.database import get_db
from sqlalchemy.ext.asyncio import AsyncSession
from app.crud.userCrud import get_user_by_username
from app.schemas.userSchema import User
from app.utils.security import verify_password
from app.exceptions import AuthException  # 导入自定义异常

# 配置
SECRET_KEY = "your-secret-key-here"  # 生产环境应该从环境变量获取
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30   #配置token有效期30分钟

# 密码哈希上下文
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")


# OAuth2 密码流
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

# Token 模型
class Token(BaseModel):
    access_token: str
    token_type: str

class TokenData(BaseModel):
    username: Optional[str] = None

# 创建token
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None, token_version: int = 0):
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=15)
    to_encode.update({
        "exp": expire,
        "v": token_version  # 👈 加入 Token 版本号
    })
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

async def authenticate_user(db: AsyncSession, username: str, password: str):
    user = await get_user_by_username(db, username)
    if not user:
        return False
    if not verify_password(password, user.hashed_password):
        return False
    return user

async def get_current_user(
        token: str = Depends(oauth2_scheme),
        db: AsyncSession = Depends(get_db)
):
    # credentials_exception = HTTPException(
    #     status_code=status.HTTP_401_UNAUTHORIZED,
    #     detail="Could not validate credentials",
    #     headers={"WWW-Authenticate": "Bearer"},
    # )
    credentials_exception = AuthException(
        detail="无效的认证凭证",
        code=40101,  # 子错误码
        msg="请提供有效的Token"
    )
    try:
        # 打印原始token用于调试
        print(f"Verifying token: {token}")
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        print(f"Decoded payload: {payload}")
        if not isinstance(payload, dict):  # <-- 新增：类型检查
            print(f"[Auth] 错误：payload不是字典，实际类型: {type(payload)}")
            raise AuthException(detail="Token格式错误", code=40104)

        username = payload.get("sub")
        if username is None:
            raise credentials_exception

        # 检查 Token 版本是否匹配
        user = await get_user_by_username(db, username=username)
        if not user:
            raise credentials_exception

        # 强制验证版本比较逻辑
        token_version = int(payload.get("v", 0))
        user_version = int(getattr(user, "token_version", 0))

        if token_version != user_version:  # 直接使用比较结果
            raise HTTPException(  # 使用原生异常
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Token已失效",
                headers={"WWW-Authenticate": "Bearer"}
            )
        return user
    except jwt.ExpiredSignatureError:
        raise AuthException(detail="Token已过期", code=40102)
    except JWTError:
        raise credentials_exception

async def get_current_active_user(current_user: User = Depends(get_current_user)):
    # 如果你不需要禁用用户的功能，直接移除相关检查：
    # if current_user.disabled:
    #     raise AuthException(
    #         detail="用户已被禁用",
    #         code=40102,  # 子错误码表示用户被禁用
    #         msg="账户不可用"
    #     )
    return current_user